
package signalprocessing;


import ikelib.PlotColor;
import ikelib.drawTools;
import ikelib.wintime;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;

import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JMenuItem;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

/**
 * 
 */

/**
 * Ｖｉｅｗの基本的な機能を提供する
 * @author Toshiharu Ikeda <ikeda.104@gmail.com>
 *
 */
abstract public class PlotPane extends JPanel {
	
	/**
	 * スケールフィットのパラメータ
	 */
	public static final int ScaleAuto_FITMaxMin = 0;
	public static final int ScaleAuto_FITCenter = 1;
	protected PlotColor Col = null;
	
	private wintime DataStartTime = new wintime(2013,1,1,0,0,0);
	private double SampleRate = 100; // Hz

	protected ScaleTools YScale = new ScaleTools();
	protected ScaleTools XScale = new ScaleTools();
	
	private HashMap<Integer,double[]> Data = new HashMap<Integer,double[]>();
	private HashMap<Integer,String> DataName = new HashMap<Integer,String>();
	private HashMap<Integer,Integer> DataSub = new HashMap<Integer,Integer>();
	protected int DataLength=0;
	private HashMap<Integer,double[]> DataX = new HashMap<Integer,double[]>();
	protected int DataXCh = 0;

	protected Rectangle ViewRect = null;;
	
	/**
	 * 凡例の表示位置、上左、上右、下右、下左、なし
	 */
	public static final int LegendPosTOP_LEFT 		= 0;
	public static final int LegendPosTOP_RIGHT 		= 1;
	public static final int LegendPosBOTTOM_RIGHT 	= 2;
	public static final int LegendPosBOTTOM_LEFT 	= 3;
	public static final int LegendPosNone 			= 4;

	/**
	 * どこに凡例を書くかを指定する。
	 * 継承したクラスはこの指定に従って凡例を描画する。
	 */
	private int LegendPosition = LegendPosTOP_LEFT;
	
	/**
	 * 凡例の表示位置を得る。
	 * @return
	 */
	public int getLegendPosition(){
		return LegendPosition;
	}
	/**
	 * 凡例の表示位置を指定する。
	 * @param pos LegendPosTOP_LEFTなど
	 */
	public void setLegendPosition(int pos){
		LegendPosition = pos;
	}

	
	public PlotPane(){
		addComponentListener(new ComponentAdapter() {
			@Override
			public void componentResized(ComponentEvent arg0) {
				onDataChange();
			}
		});
		//super();
	}
	
	
	protected PlotAxis YAxis = null;
	protected PlotAxis XAxis = null;
	protected PlotAxis TAxis = null;
	
	/**
	 * Ｙ軸をセットする。
	 * @param y
	 * @param col
	 */
	protected void setYaxis(PlotAxis y,PlotColor col){
		YAxis=y;
		YAxis.Col = col;
		y.setParent(this);
	}
	/**
	 * Ｘ軸をセットする。
	 * @param x
	 * @param col
	 */
	protected void setXaxis(PlotAxis x,PlotColor col){
		XAxis=x;
		XAxis.Col = col;
		x.setParent(this);
	}
	/**
	 * Ｔ（時刻）軸をセットする。
	 * @param x
	 * @param col
	 */
	protected void setTaxis(PlotAxis x,PlotColor col){
		TAxis=x;
		TAxis.Col = col;
		x.setParent(this);
	}
	/**
	 * Y軸を得る
	 * @return
	 */
	public PlotAxis getYAxis(){
		return YAxis;
				
	}
	/**
	 * Ｘ軸を得る
	 * @return
	 */
	public PlotAxis getXAxis(){
		return XAxis;
				
	}
	/**
	 * Ｔ軸を得る。
	 * @return
	 */
	public PlotAxis getTAxis(){
		return TAxis;
				
	}
	
	/**
	 *　描画色をセットする。
	 * @param col
	 */
	public void setPlotColor(PlotColor col){
		Col = col;
	}
	
	public class ScaleTools{
		protected double ScaleCenter = 0.0;
		protected double ScaleAmp = 10.0;
		
		protected double  TempDispDataMax=0; // 
		protected double  TempDispDataMin=0;
		
		public double getScaleMax(){
			return ScaleCenter + ScaleAmp;
		}
		public double getScaleMin(){
			return ScaleCenter - ScaleAmp;
		}
		public double getScaleCenter(){
			return ScaleCenter;
		}
		public double getScaleSpan(){
			return ScaleAmp*2.0;
		}
		public void setScaleMaxMin(double max,double min){
			if(max<=min) return;
			ScaleCenter = (max+min)/2.0;
			ScaleAmp = (max-min)/2.0;
		}
		/**
		 * center , span でＹ表示範囲を指定する。
		 * @param cen　
		 * @param span
		 */
		public void setScale(double cen,double span){
			if(span<=0.0) return;
			ScaleCenter = cen;
			ScaleAmp = span;
		}
		/**
		 * Ｙ軸スパンを設定する センターは変更しない
		 * @param span
		 */
		public void setScaleSpan(double span){
			if(span<=0.0) return;
			ScaleAmp = span/2.0;
		}
		/**
		 * Ｙ軸センターを設定する。　スパンは変更しない
		 * @param cen
		 */
		public void setScaleCenter(double cen){
			ScaleCenter = cen;
		}
		public void setScaleCenterByRatio(double ratio){
			ScaleCenter += ratio * ScaleAmp;
		}
		/**
		 * Ｙ軸スパンをきりのいい数字に変更する。
		 * @param digit　有効桁を指定する。　1= 1.20e-1 2=1.230e-3 のようになる
		 */
		public void setScaleSpanRound(int digit){
			if(digit < 0) return;
			String fmt = String.format("%%.%de", digit);
			double ymax = ScaleAmp+ScaleCenter;
			String str = String.format(fmt,ymax);
			ymax = Double.valueOf(str);
			double ymin = -ScaleAmp+ScaleCenter;
			str = String.format(fmt,ymin);
			ymin = Double.valueOf(str);
			setScaleMaxMin(ymax,ymin);
		}
		/**
		 * 振幅軸を自動設定する。
		 * 
		 * @param mode <BR>
		 *  YScaleAuto_FITMaxMin: データの最大値、最小値に合わせる <BR>
		 *  YScaleAuto_FITCenter: センターを０にして、データの最大値あるいは最小値に振幅を合わせる。<BR>
		 */
		public void setScaleAuto(int mode){
			if(TempDispDataMax != -Double.MAX_VALUE && TempDispDataMin!=Double.MAX_VALUE){
				if(mode == ScaleAuto_FITMaxMin){
					ScaleCenter = (TempDispDataMax + TempDispDataMin)/2.0;
					ScaleAmp    = (TempDispDataMax - TempDispDataMin)/2.0;
				}
				else{
					ScaleCenter = 0.0;
					double a = Math.abs(TempDispDataMax);
					double b = Math.abs(TempDispDataMin);
					if(a  > b) ScaleAmp = a;
					else       ScaleAmp = b;
				}
			}
		}
		/**
		 * スパンを拡大縮小する。
		 * @param ratio int %で指定。＋１０のとき、スパン＋１０％
		 */
		public void setScaleUpDown(int ratio){
			ScaleAmp *= ratio/100.0;
		}
		/**
		 * センターを移動させる。
		 * @param ratio　int %で指定。+10のとき、center = center + Span*10% 
		 */
		public void setScaleShift(int ratio){
			ScaleCenter +=  ScaleAmp * (ratio/100.0);
		}
		
	}
	
	//// 振幅関係　/////////////////////////
	public double getYScaleMax(){
		return YScale.getScaleMax();
	}
	public double getXScaleMax(){
		return XScale.getScaleMax();
	}
	public double getYScaleMin(){
		return YScale.getScaleMin();
	}
	public double getXScaleMin(){
		return XScale.getScaleMin();
	}
	public double getYScaleCenter(){
		return YScale.getScaleCenter();
	}
	public double getXScaleCenter() {
		return XScale.getScaleCenter();
	}

	
	public double getYScaleSpan(){
		return YScale.getScaleSpan();
	}
	public double getXScaleSpan(){
		return XScale.getScaleSpan();
	}
	public void setYScaleMaxMin(double max,double min,boolean rp){
		YScale.setScaleMaxMin(max,min);
		if(rp) onDataChange();
	}
	public void setXScaleMaxMin(double max,double min,boolean rp){
		XScale.setScaleMaxMin(max,min);
		if(rp) onDataChange();
	}
	/**
	 * center , span でＹ表示範囲を指定する。
	 * @param cen　
	 * @param span
	 */
	public void setYScale(double cen,double span){
		YScale.setScale(cen,span);
		onDataChange();
	}
	public void setXScale(double cen,double span){
		XScale.setScale(cen,span);
		onDataChange();
	}
	/**
	 * Ｙ軸スパンを設定する センターは変更しない
	 * @param span
	 */
	public void setYScaleSpan(double span){
		YScale.setScaleSpan(span);
		onDataChange();
	}
	/**
	 * Ｘ軸スパンを設定する センターは変更しない
	 * @param span
	 */
	public void setXScaleSpan(double span){
		XScale.setScaleSpan(span);
		onDataChange();
	}
	/**
	 * Ｙ軸センターを設定する。　スパンは変更しない
	 * @param cen
	 */
	public void setYScaleCenter(double cen){
		YScale.setScaleCenter(cen);
		onDataChange();
	}
	/**
	 * Ｘ軸センターを設定する。　スパンは変更しない
	 * @param cen
	 */
	public void setXScaleCenter(double cen){
		XScale.setScaleCenter(cen);
		onDataChange();
	}
	/**
	 * Ｙ軸スケールのセンターを指定割合だけシフトする
	 * @param ratio
	 */
	public void setYScaleCenterByRatio(double ratio){
		YScale.setScaleCenterByRatio(ratio);
		onDataChange();
	}
	/**
	 * Ｘ軸スケールのセンターを指定割合だけシフトする
	 * @param ratio
	 */
	public void setXScaleCenterByRatio(double ratio){
		XScale.setScaleCenterByRatio(ratio);
		onDataChange();
	}
	/**
	 * Ｙ軸スパンをきりのいい数字に変更する。
	 * @param digit　有効桁を指定する。　1= 1.20e-1 2=1.230e-3 のようになる
	 */
	public void setYScaleSpanRound(int digit){
		YScale.setScaleSpanRound(digit);
		onDataChange();
	}
	/**
	 * Ｘ軸スパンをきりのいい数字に変更する。
	 * @param digit　有効桁を指定する。　1= 1.20e-1 2=1.230e-3 のようになる
	 */
	public void setXScaleSpanRound(int digit){
		XScale.setScaleSpanRound(digit);
		onDataChange();
	}
	
	/**
	 * 振幅軸を自動設定する。
	 * 
	 * @param mode <BR>
	 *  YScaleAuto_FITMaxMin: データの最大値、最小値に合わせる <BR>
	 *  YScaleAuto_FITCenter: センターを０にして、データの最大値あるいは最小値に振幅を合わせる。<BR>
	 */
	public void setYScaleAuto(int mode){
		YScale.setScaleAuto(mode);
		onDataChange();
	}
	/**
	 * X軸を自動設定する。
	 * @param mode <BR>
	 *  YScaleAuto_FITMaxMin: データの最大値、最小値に合わせる <BR>
	 *  YScaleAuto_FITCenter: センターを０にして、データの最大値あるいは最小値に振幅を合わせる。<BR>
	 */
	public void setXScaleAuto(int mode){
		XScale.setScaleAuto(mode);
		onDataChange();
	}
	/**
	 * Ｙスパンを拡大縮小する。
	 * @param ratio int %で指定。＋１０のとき、スパン＋１０％
	 */
	public void setYScaleUpDown(int ratio){
		YScale.setScaleUpDown(ratio);
		onDataChange();
	}
	/**
	 * Ｘスパンを拡大縮小する。
	 * @param ratio int %で指定。＋１０のとき、スパン＋１０％
	 */
	public void setXScaleUpDown(int ratio){
		XScale.setScaleUpDown(ratio);
		onDataChange();
	}
	/**
	 * Ｙ軸のセンターを移動させる。
	 * @param ratio　int %で指定。+10のとき、center = center + Span*10% 
	 */
	public void setYScaleShift(int ratio){
		YScale.setScaleShift(ratio);
		onDataChange();
	}
	/**
	 * Ｘ軸のセンターを移動させる。
	 * @param ratio　int %で指定。+10のとき、center = center + Span*10% 
	 */
	public void setXScaleShift(int ratio){
		XScale.setScaleShift(ratio);
		onDataChange();
	}
	
	/**
	 * Ｙ軸のmax、minをセットする。
	 * @param max
	 * @param min
	 */
	public void setYScaleMaxMin(double max, double min) {
		YScale.setScaleMaxMin(max, min);
		onDataChange();
	}

	/**
	 * Ｘ軸のmax、minをセットする。
	 * @param max
	 * @param min
	 */
	public void setXScaleMaxMin(double max, double min) {
		XScale.setScaleMaxMin(max, min);
		onDataChange();
	}

	
	
	//// 時間関係　/////////////////////////
	/**
	 *　データのスタート時間をセットする。
	 * @param st　tintime
	 */
	public void setDataStartTime(wintime st,boolean rp){
		DataStartTime = new wintime(st);
		if(rp) onDataChange();
	}
	/**
	 * wintimeな表示スタート時刻を得る
	 * @return
	 */
	public wintime getDataStartTime(){
		return new wintime(DataStartTime);
	}
	/**
	 * 表示開始時刻をwintimeで得る
	 * @return
	 */
	public wintime getViewStartTime(){
		double  elapse = calcViewTimeStart()/SampleRate;//経過時間
		wintime ret = new wintime(DataStartTime);
		if(elapse >0) ret.inc_msec((int)(elapse*1000));
		return ret;
	}
	/**
	 * 表示時間範囲を秒で得る
	 * @return
	 */
	public double getViewTimeSpanSec(){
		return calcViewTimeSpan()/SampleRate;
	}
	/**
	 * 表示するスタート時間（サンプル単位）を得る
	 * @return
	 */
	public int getViewTimeStart() {
		return calcViewTimeStart();
	}
	/**
	 * 表示するタイムスパン（サンプル単位）を得る）
	 * @return
	 */
	public int getViewTimeSpan() {
		return calcViewTimeSpan();
	}
	/**
	 * 表示する時間を自動セットする
	 */
	public void setTimeSpanAuto(boolean rp) {
		setViewTimeStart(0,rp);
		setViewTimeSpan(DataLength,rp);
		onDataChange();
	}
	/**
	 * 表示するスタート時間（サンプル単位）セットする
	 * @param viewTimeStart
	 */
	public void setViewTimeStart(int v,boolean rp) {
		if(v<0) v=0;
		int span = calcViewTimeSpan();
		if(span<10) span=10;
		double max = v + span;
		double min = v;
		setXScaleMaxMin(max,min,rp);
		//if(rp) onDataChange();
	}
	/**
	 * 表示するタイムスパン（サンプル単位を）セットする
	 * @param viewTimeSpan
	 */
	public void setViewTimeSpan(int viewTimeSpan,boolean rp) {
		int v = viewTimeSpan;
		if(v<10) v=10;
		double max = calcViewTimeStart() + v;
		double min = calcViewTimeStart();
		setXScaleMaxMin(max,min,rp);
		//if(rp) onDataChange();
	}
	/**
	 * 表示するスタート時間（サンプル単位）増減する
	 * @param inc % で指定する。
	 */
	public void incViewTimeStart(int inc) {
		int v = (int)(calcViewTimeStart() + (double)(calcViewTimeSpan() * inc) / 100.0);
		if(v<0) v=0;
		setViewTimeStart(v,true);
		onDataChange();
	}
	/**
	 * 表示するタイムスパン（サンプル単位を）増減する
	 * @param inc %で指定する
	 */
	public void incViewTimeSpan(int inc) {
		int v = (int)(calcViewTimeSpan() + (double)(calcViewTimeSpan() * inc) / 100.0);
		if(v<10) v=10;
		setViewTimeSpan(v,true);
		onDataChange();
	}
	/**
	 * サンプルレートをセットする。
	 * @param smp
	 */
	protected void setSampleRate(double smp,boolean rp){
		SampleRate=smp;
		if(rp) onDataChange();
	}
	/**
	 * サンプルレートをゲットする。
	 * @return
	 */
	protected double getSampleRate(){
		return SampleRate;
	}
	protected int calcViewTimeStart() {
		return (int)(getXScaleCenter()-getXScaleSpan()/2);
	}
	protected int calcViewTimeSpan(){
		return (int)getXScaleSpan();
	}

//-------------------------------------------------------------------------------------------------
	
	
	
	
	//-------------------------------------------------------------------------------------------------
	//-------------------------------------------------------------------------------------------------
	
	
	
	
	
	
	
	
	/**
	 * データが変化したときに呼び出される
	 */
	abstract void onDataChange();
	/**
	 * max minでＹ表示範囲を指定する。
	 * @param max
	 * @param min
	 */
	//// データ関係　/////////////////////////
	/**
	 * データをセットする。
	 * @param id int channelID
	 * @param d double[] データ
	 */
	public void setData(int id,int subid,String name,double[] d){
		if(DataLength==0) DataLength=d.length;
		if(d.length != DataLength) return;
		Data.put(id,d);
		DataSub.put(id,subid);
		DataName.put(id, name);
		onDataChange();
	}
	public void setData(int id,int subid,String name,double[] d,int idx,double[] dx){
		if(DataLength==0) DataLength=d.length;
		if(d.length != DataLength) return;
		Data.put(id,d);
		DataX.put(idx,dx);
		DataXCh = idx;
		DataSub.put(id,subid);
		DataName.put(id, name);
		onDataChange();
	}
	/**
	 * データの長さ
	 * @return
	 */
	public int getDataLength(){
		return DataLength;
	}
	/**
	 * 保持しているchannel IDの配列を得る。
	 * @return
	 */
	public Integer[] getChannel(){
		Set<Integer> s = Data.keySet();
		Integer [] ret = new Integer[s.size()];
		ret = s.toArray(new  Integer[1]);
		return ret;
	}
	/**
	 * データを得る。
	 * @param ch
	 * @return
	 */
	public double[] getData(int ch){
		double[] ret = Data.get(ch);
		return ret;
	}
	/**
	 * データを得る。
	 * @param ch
	 * @return
	 */
	public double[] getDataX(int ch){
		double[] ret = DataX.get(ch);
		return ret;
	}
	/**
	 * データ名を得る。
	 * @param ch
	 * @return
	 */
	public String getDataName(int ch){
		String ret = DataName.get(ch);
		return ret;
	}
	public int getIdSub(int ch){
		return DataSub.get(ch);
	}

	/**
	 * グラフを描画するべきRectangleをセットする
	 * 
	 * @param v　
	 */
	protected void setViewRect(Rectangle v){
		ViewRect = v;
	}
	
	
	protected HashMap<Integer,int[]> PolyDataX = new HashMap<Integer,int[]>();
	protected HashMap<Integer,int[]> PolyDataY = new HashMap<Integer,int[]>();
	protected HashMap<Integer,Integer> PolyDataLen = new HashMap<Integer,Integer>();
	
	abstract boolean PolyLineCalc();
	abstract boolean PointCalc();
	
	/**
	 * 凡例を描画する
	 * 
	 * @param g2　
	 * @param name  表示する文字列のリスト
	 * @param HMargin　水平ｊ方向のマージン
	 * @param VMargin　垂直方向のマージン
	 * @param drawPoint　文字の左に線を描くかどうか 0:直線を描く、１:ＩＤから自動的にシェイプを選択する。-1：書かない
	 */
	protected Rectangle Legend(Graphics2D g2,LinkedList<String> name,int HMargin,int VMargin,int drawPoint){
		
		Dimension dm = this.getSize();
		// 凡例を描画
		int legendPos = getLegendPosition();
		if(legendPos == LegendPosNone) return null;// 
		
		int x = 0;
		int y = 0;
		int pos  = 0; 
		int linesize = 4;
		int linemargin = 4;
		if(drawPoint>=0){
			x += (linesize*2 + linemargin);
		}
		
		switch(legendPos){
		case LegendPosTOP_LEFT:
			x += HMargin;
			y = VMargin;
			pos = drawTools.POSITION_LEFT_TOP|drawTools.FILL_RECT;
			break;
		case LegendPosTOP_RIGHT:
			x += dm.width - HMargin - (linesize*2 + linemargin);
			y = VMargin;
			pos = drawTools.POSITION_RIGHT_TOP|drawTools.FILL_RECT;
			break;
		case LegendPosBOTTOM_RIGHT:
			x += dm.width - HMargin - (linesize*2 + linemargin);
			y = dm.height - VMargin;
			pos = drawTools.POSITION_RIGHT_BOTTOM|drawTools.FILL_RECT;
			break;
		case LegendPosBOTTOM_LEFT:
			x += HMargin;
			y = dm.height - VMargin;
			pos = drawTools.POSITION_LEFT_BOTTOM|drawTools.FILL_RECT;
			default:
		}
		// 文字列のリストを渡して文字を描画
		if(Col!=null) g2.setColor(Col.ColorTextInfo);
		Rectangle rec = drawTools.drawText(g2, name, x,y,pos,true);
		
		Integer[] id = getChannel();
		int linehight = rec.height / name.size();
		
		if(drawPoint>=0){
			Stroke s = g2.getStroke();
			g2.setStroke(StrokeBold);
			for(int i=0;i<id.length;i++){
				if(Col!=null) g2.setColor(Col.getDataColor(id[i]));
				int shape = 0;
				if(drawPoint>0) shape = getPointShape(id[i]);
				else if( shape < 0) shape = -1;
				//drawPointShape(g2,linemargin+linesize,VMargin + linehight*i+linehight/2 ,shape,linesize);
				drawPointShape(g2,rec.x-linesize-linemargin, rec.y + linehight*i+linehight/2 ,shape,linesize);
			}
			g2.setStroke(s);
		}
		
		return rec;
		
	}
	/**
	 * ポイントのシェイプ番号を得る
	 * @param id
	 * @return
	 */
	private int getPointShape(int id){
		
		return (id % ShapeEND) + 1;
	}
	/**
	 * 
	 * Polylineを描画する
	 * @param g
	 */
	protected void PolyLine(Graphics2D g){
		g.clipRect(ViewRect.x, ViewRect.y, ViewRect.width, ViewRect.height);
		// View Portの原点を
		int sftx = ViewRect.x;
		int sfty = ViewRect.y+(ViewRect.height-1)/2;
		g.translate(sftx, sfty);
		
		Integer[] id = getChannel();
		if(DrawCenter){
			//int ycen = (int)(-(-YScale.ScaleCenter)/YScale.ScaleAmp * (ViewRect.height)/2.0);
			//g.drawLine(ViewRect.x, ycen, ViewRect.width, ycen);
		}
		for(int i=0;i<id.length;i++){
			if(Col!=null) g.setColor(Col.getDataColor(id[i]));
			int[] datx = PolyDataX.get(id[i]);
			int[] daty = PolyDataY.get(id[i]);
			Integer start  = PolyDataLen.get(id[i]);
			if(datx != null && daty != null){
				g.drawPolyline(datx, daty, start);
			}
		}
		g.translate(-sftx, -sfty);
		g.setClip(null);
	}
	
	/**
	 * 
	 * @param g
	 */
	private BasicStroke StrokeBold = new BasicStroke(3.0f);
	/**
	 * ＸＹプロットを描画する。
	 * @param g
	 */
	protected void PlotPoint(Graphics2D g){
		g.clipRect(ViewRect.x, ViewRect.y, ViewRect.width, ViewRect.height);
		
		// View Portの原点を
		int sftx = ViewRect.x+(ViewRect.width-1)/2;
		int sfty = ViewRect.y+(ViewRect.height-1)/2;
		g.translate(sftx, sfty);
		
		Integer[] id = getChannel();
		if(DrawCenter){
			//int ycen = (int)(-(-YScale.ScaleCenter)/YScale.ScaleAmp * (ViewRect.height)/2.0);
			//g.drawLine(ViewRect.x, ycen, ViewRect.width, ycen);
		}
		
		Stroke s = g.getStroke();
		// プロットは太い線で描画
		g.setStroke(StrokeBold);
		for(int i=0;i<id.length;i++){
			// 色をかえて
			if(Col!=null) g.setColor(Col.getDataColor(id[i]));
			int[] datx = PolyDataX.get(id[i]);
			int[] daty = PolyDataY.get(id[i]);
			if(datx != null && daty != null){
				for(int j=0;j<datx.length;j++){
					drawPointShape(g,datx[j],daty[j],getPointShape(id[i]),4);
				}
			}
		}
		g.translate(-sftx, -sfty);
		g.setClip(null);
		
		// 凡例を描画
//		int xpos = 10;
//		int ypos = 10;
//		int ydelta = 20;
//		for(int i=0;i<id.length;i++){
//			String title = DataName.get(id[i]);
//			if(title==null) continue;
//			if(Col!=null) g.setColor(Col.getDataColor(id[i]));
//			drawPointShape(g,xpos,ypos,i%9+1,4);
//			drawTools.drawText(g, title, xpos + 10, ypos, drawTools.POSITION_LEFT_CENTER);
//			ypos += ydelta;
//		}
		LinkedList<String> lst = new LinkedList<String>();
		for(int i=0;i<id.length;i++){
			String title = DataName.get(id[i]);
			lst.add(title);
		}
		Legend(g,lst,10,10,1);
		g.setStroke(s);
		
	}
	/**
	 * ポイントを描画する時の、ポイントの形
	 */
	public static final int ShapeLINE = 0;// 直線（ポイント出ないときに使う）
	public static final int ShapeX    = 1;
	public static final int ShapeRect = 2;
	public static final int ShapeTriU = 3;
	public static final int ShapeTriD = 4;
	public static final int ShapeDia  = 5;
	public static final int ShapePlus = 6;
	public static final int ShapeAstr = 7;
	public static final int ShapeTriL = 8;
	public static final int ShapeTriR = 9;
	public static final int ShapeEND = 9;
	/**
	 * いろいろなポイントを描画する。
	 * @param g
	 * @param x
	 * @param y
	 * @param shape　ShapeXなど
	 * @param size　ポイントの長さの半分　pixelで指定する
	 */
	private void drawPointShape(Graphics2D g,int x,int y,int shape,int size){
		int[] xp = new int[4];
		int[] yp = new int[4];
		switch(shape){
		case ShapeLINE:   
			g.drawLine(x-size,y,x+size,y);
			break;
		case ShapeX:   
			g.drawLine(x-size,y-size,x+size,y+size);
			g.drawLine(x+size,y-size,x-size,y+size);
			break;
		case ShapeRect:
			g.drawRect(x-size,y-size,size*2,size*2);
			break;
		case ShapeTriU:
			xp[0] = x; yp[0] = y-size;
			xp[1] = x-size; yp[1] = y+size;
			xp[2] = x+size; yp[2] = y+size;
			g.drawPolygon(xp,yp,3);
			break;
		case ShapeTriD:
			xp[0] = x; yp[0] = y+size;
			xp[1] = x-size; yp[1] = y-size;
			xp[2] = x+size; yp[2] = y-size;
			g.drawPolygon(xp,yp,3);
			break;
		case ShapeDia:
			xp[0] = x; yp[0] = y-size;
			xp[1] = x-size; yp[1] = y;
			xp[2] = x; yp[2] = y+size;
			xp[3] = x+size; yp[3] = y;
			g.drawPolygon(xp,yp,4);
			break;
		case ShapePlus:
			g.drawLine(x,y-size,x,y+size);
			g.drawLine(x+size,y,x-size,y);
			break;
		case ShapeAstr:
			g.drawLine(x,y-size,x,y+size);
			g.drawLine(x+size,y,x-size,y);
			g.drawLine(x-size,y-size,x+size,y+size);
			g.drawLine(x+size,y-size,x-size,y+size);
			break;
		case ShapeTriL:
			xp[0] = x-size; yp[0] = y;
			xp[1] = x+size; yp[1] = y+size;
			xp[2] = x+size; yp[2] = y-size;
			g.drawPolygon(xp,yp,3);
			break;
		case ShapeTriR:
		default:
			xp[0] = x+size; yp[0] = y;
			xp[1] = x-size; yp[1] = y-size;
			xp[2] = x-size; yp[2] = y+size;
			g.drawPolygon(xp,yp,3);
			break;
		}
	}
	protected boolean DrawCenter = false;
	/**
	 * センターライン（横）を書く
	 * @param g
	 * @param r
	 */
	protected void drawZero(boolean draw){
		DrawCenter=draw;
	}
	public void onAxisDragEnter(){
		
	}
	public void onAxisDragging(double ratio){
		
	}
	public void onAxisDragEnd(){
		
	}
	
	abstract void repaintAllComponent();
	public void repaintAll(){
		repaintAllComponent();
	}
	private static void addPopup(Component component, final JPopupMenu popup) {
		component.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				if (e.isPopupTrigger()) {
					showMenu(e);
				}
			}
			public void mouseReleased(MouseEvent e) {
				if (e.isPopupTrigger()) {
					showMenu(e);
				}
			}
			private void showMenu(MouseEvent e) {
				popup.show(e.getComponent(), e.getX(), e.getY());
			}
		});
	}
}

	
